---
title: Convert (request-shaped)
summary: Converts a source document to PDF (or PDF/A) using a request DTO, with tracking, retry, and failure-email side effects.
status: draft
owner: Not determined from source
last_reviewed: 2026-09-17
library: PdfAPI
reference_type: embedded
operation_id: OP-CONVERT-REQUEST
trigger: Client submits a POST v1/convert request with a ConvertRequest body
---

# OP-CONVERT-REQUEST: Convert (request-shaped)

Converts a source document (embedded in the request DTO) to PDF or PDF/A, selecting the processor from configuration, tracking the request, and optionally notifying on failure.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-CONVERT-REQUEST |
| **Trigger** | Client submits `POST v1/convert` with a `ConvertRequest` body |
| **Entry endpoint** | [`POST v1/convert`](../endpoints/convert-controller.md#post-v1%2Fconvert) |
| **Owning component** | `ConvertController.Convert(ConvertRequest)` → `IPdfService.Convert(request)` |
| **Inputs** | `ConvertRequest` body (source document bytes/metadata, `Options`, `SkipPdf`, `TrackingEnabled`, `SendHeatEmailOnFailure`) |
| **Outputs** | `PdfResult` (`Status`, `Message`, `Document`, `TrackingId`); a `PDFTracking` row created/updated; optionally an incident email |
| **Failure response** | Caught exceptions are logged and returned as `Ok(new PdfResult(message))` — HTTP `200` |

## Steps

1. The action wraps the call in `try`/`catch` ([BR-PDFAPI-017](../business-rules.md#br-pdfapi-017-processing-failures-return-200-with-a-pdfresult)).
   - On any exception: `_logService.LogException("pdfapi", "Convert", "<detail>", ex)`, then `Ok(new PdfResult(ex.Message, request: request))` — HTTP `200`, produced by the action's own `catch` block, not the framework.
2. `PdfServiceFactory.Create()` reads `pdfapi.pdfservicetype` and returns `ActivePdfService` for `"activepdf"`, otherwise `SyncfusionPdfService` ([BR-PDFAPI-003](../business-rules.md#br-pdfapi-003-processor-selection-by-configuration)).
3. If tracking is enabled (default, or forced on by `SendHeatEmailOnFailure`, [BR-PDFAPI-010](../business-rules.md#br-pdfapi-010-tracking-forced-on-with-heat-email)), `PdfTrackingService.CreateTrackingRecord` inserts a `PDFTracking` row with status `SCHED` ([data model](../data-model.md#pdftracking-properties-observed-in-use)), then updates it to `PROC`.
4. When `pdfapi.saveInputToTemp` is enabled, the inbound document is written to temporary storage before conversion ([BR-PDFAPI-016](../business-rules.md#br-pdfapi-016-save-input-to-temp-storage)).
5. On the Syncfusion path (default), `ConverterFactory.Convert(request)` dispatches on the lower-cased, trimmed file extension:
   - An unrecognized extension returns a failure `PdfResult` whose `Status` is left at the enum default `NotTracked`, not `Failed` ([BR-PDFAPI-008](../business-rules.md#br-pdfapi-008-unsupported-extension-leaves-status-at-default)).
   - Plain-text (`.txt`) input is converted twice: to an intermediate document, then to PDF ([BR-PDFAPI-009](../business-rules.md#br-pdfapi-009-plain-text-double-conversion)).

   This conversion logic is implemented in `PdfApi.SyncFusionCore` (`ConverterFactory.Convert`) and is documented in full at [Convert a source document to PDF](../../../libraries/pdfapi-syncfusioncore/operations/convert-source-document-to-pdf.md) (OP-SFC-001); its behavior is summarized here only as observed on this request path.

   > **Origin:** The extension-dispatch, unrecognized-extension, and plain-text double-conversion
   > behaviors described in this step are implemented in `PdfApi.SyncFusionCore`, not in `PdfAPI`.
   > See the linked operation page for the full delegated logic.
6. On the ActivePDF path (`pdfapi.pdfservicetype == "activepdf"`): if `SkipPdf` is set (default `true`) and the input is already a PDF, conversion is short-circuited and the input is returned as the output ([BR-PDFAPI-019](../business-rules.md#br-pdfapi-019-skip-conversion-when-input-is-already-pdf)). A PDF/A production failure is retried as plain PDF, and configured `pdfApi.ErrorsToRetry` error codes trigger a whole-operation retry ([BR-PDFAPI-020](../business-rules.md#br-pdfapi-020-activepdf-retry-behavior)).
7. `FinalizeResult` stamps `TrackingId`, `PdfProcessorType`, `FilePath` on the result, then persists the terminal tracking status (`SUCC`/`ERROR`) via `PdfTrackingService.UpdateTrackingRecord`.
8. If the result failed and `SendHeatEmailOnFailure` is set, `PdfService.SendIncidentEmail` sends a notification using `noreplyemailsenderaddress`/`pdfapi.ErrorEmail.Recipient` and the tracking record's `ApplicationError.HeatEmailSubject` ([BR-PDFAPI-015](../business-rules.md#br-pdfapi-015-incident-email-on-failure)).
9. The controller returns `Ok(result)` — HTTP `200` regardless of whether the conversion succeeded or failed.

## Process flow

The following diagram shows the processor-selection, tracking, and incident-email sequence for a conversion request.

```mermaid
flowchart TD
    A["POST v1/convert"] --> B["PdfServiceFactory.Create selects processor"]
    B --> C["Create tracking record<br>SCHED to PROC"]
    C --> D{"Processor"}
    D -->|Syncfusion default| E["ConverterFactory.Convert"]
    D -->|ActivePDF| F["ActivePdfService.Convert"]
    E --> G["FinalizeResult: persist terminal status"]
    F --> G
    G --> H{"Result failed and<br>SendHeatEmailOnFailure?"}
    H -->|Yes| I["Send incident email"]
    H -->|No| J["Ok result"]
    I --> J
```

## Transaction and side effects

| Aspect | Finding |
| --- | --- |
| Unit of work | `IUnitOfWorkFactory("oracle")`, `InstancePerRequest` |
| Commit point | `PdfTrackingService.CreateTrackingRecord` and `UpdateTrackingRecord`, each bracketed by `_uow.Begin()`/`_uow.Commit()` |
| Records written | `PDFTracking` ([data model](../data-model.md#pdftracking-properties-observed-in-use)) |
| Downstream calls | Outbound SMTP email on failure when `SendHeatEmailOnFailure` is set |
| Repeat-call behavior | Each call creates a new tracking record; not idempotent |

## Logging

| Surface | Written content |
| --- | --- |
| `ILogService.LogException` | `"pdfapi"`, `"Convert"`, and exception detail, on any caught failure |
| `ILogService.TraceError` / `TraceWarn` / `TraceDebug` | Emitted from `ActivePdfService` on the ActivePDF processor path |

## Error handling

- Any exception during processing: caught in the action, logged via `ILogService.LogException`, returned as `Ok(new PdfResult(message))` — HTTP `200` ([BR-PDFAPI-017](../business-rules.md#br-pdfapi-017-processing-failures-return-200-with-a-pdfresult)).
- Unrecognized file extension: not an exception — a failure `PdfResult` with `Status == NotTracked` ([BR-PDFAPI-008](../business-rules.md#br-pdfapi-008-unsupported-extension-leaves-status-at-default)).

## Related documentation
- [API index](../index.md)
- [Overview](../overview.md)
- [Architecture](../architecture.md)
- [Endpoints](../endpoints.md)
- [Authentication and authorization](../authentication-authorization.md)
- [Dependencies](../dependencies.md)
- [Configuration](../configuration.md)
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)
- [Data model](../data-model.md)
- [Operational runbook](../operational-runbook.md)
- [Tech debt](../tech-debt.md)

## Sources
- PdfAPI\Controllers\v1\ConvertController.cs
- PdfAPI\Services\PdfServiceFactory.cs
- PdfAPI\Services\PdfService.cs
- PdfAPI\Services\PdfTrackingService.cs
- PdfAPI\Services\ActivePdf\ActivePdfService.cs
- PdfApi.SyncFusionCore\Convert\ConverterFactory.cs
